---
title: SAIF.Business.Claim.Legal architecture
summary: Architectural responsibilities, boundaries, and interaction patterns for the legal-case business/domain library.
status: draft
owner: SAIF Case Management team
last_reviewed: 2026-08-21
library: SAIF.Business.Claim.Legal
reference_type: embedded
---

# SAIF.Business.Claim.Legal architecture

SAIF.Business.Claim.Legal is the largest and most central business/domain library in this application, comprising 58 `.vb` files and 96 framework-derived classes across four functional areas: the legal-case aggregate (`LegalNet\`), attorney/reference-data maintenance (`TableMaint\`), a REST DTO surface (`LegalApi\`), and print/letter generation (`Print\`). It sits in the BOF "Business Component" tier between the (out-of-scope) presentation layer and the Oracle database, and additionally acts as a REST client/DTO producer for a separate legal/claim API integration tier.

## Responsibilities
- Model and persist the legal-case aggregate and its lifecycle sub-entities: case header, status history, appeals/board actions, case cost/outcomes, hearings/schedules, mail dates, consolidations, acknowledgements, file locations, and case notes (`LegalNet\`).
- Maintain attorney/firm/legal-person reference and assignment data largely independent of the case aggregate (`TableMaint\`): attorney profiles, conflicts, policy assignments, schedules, hearing locations, other firms, legal persons, and rotation assignments.
- Project internal business objects into REST request/response DTO shapes for a legal/claim integration API (`LegalApi\`), and provide a print/letter-generation subsystem that assembles print-ready content from both local business objects and REST calls (`Print\`).
- Supply cross-cutting static code-table/lookup access (`mdlCodeTables.vb`) consumed across most of the above domains for dropdown/code-table data.
- Carry auto-generated typed-DataSet scaffolding (`Institutions.Designer.vb`) for bank/institution reference data used with `BankValidator`.*

## Component boundaries
- **LegalNet (legal-case aggregate)**: owns the case header (`clsLegalCase`) and its dependent sub-entities (status history, appeals, case cost/outcomes, hearings/schedules, mail dates, consolidations, acknowledgements, file locations, notes, evaluations). Persists primarily via Oracle stored procedures/inline SQL through `IBusinessCriteria`, with one confirmed hybrid path to a REST API client (`clsLegalCase.CheckForOtherCases()`).
- **TableMaint (reference/master data)**: attorney, firm, hearing-location, legal-person, and assignment/rotation maintenance entities; mostly simple CRUD with `AddBusinessRules()` validation, connected to the case aggregate only through foreign-key-style lookups rather than direct object composition.
- **LegalApi (DTO/API surface)**: plain data-transfer classes (`<Entity>Data` envelope + payload class per resource) with no business logic; used to project business objects into REST payloads for cross-application interop.
- **Print (letter generation)**: `clsLetterRequest`/`clsLetterRequestCollection` retrieve and assemble print-ready letter content by calling `LegalApi` REST endpoints (e.g. `v1/Integration/LetterRequests`, `v1/Integration/WorkerInfo/{id}`, `v1/Integration/WorkerAtty/{id}`) rather than SQL; its `IBusinessCriteria` implementation always throws `InvalidSQLProperty`, confirming an API-backed rather than SQL-backed data path — the same behavioral pattern documented for `clsBusinessApiCriteriaBase` in the framework's own documentation.†
- **mdlCodeTables (cross-cutting lookups)**: a static module used by most domains above for code-table/dropdown data; not owned by any single aggregate.
- **Institutions.Designer.vb (scaffolding)**: auto-generated typed `DataSet` for bank/institution data; not hand-authored business logic.*

## Interaction model
- The (out-of-scope) presentation layer invokes public methods/properties on `clsBusinessBase`-derived entities and `clsBusinessCollection`-derived collections; these dispatch through the inherited framework data-portal path (`SAIF.Framework.Core`†) to Oracle stored procedures/inline SQL (`Pk80001_Legalnet.*`, `Pk80005_assignment.*`) or, for API-backed objects, to a named `IApiClient` resolved via `GetApiClient()`/`FormatRoute()`.†
- `LegalNet\clsLegalCase.CheckForOtherCases()` and the entire `Print\` subsystem call out to the `LegalApi`/integration REST tier (`DataPortalInfo.ApiClients("LegalApi")`, routes such as `v1/integration/LetterRequests`, `v1/integration/WorkerInfo/{id}`, `v1/integration/WorkerAtty/{id}`) — a hybrid SQL + REST data-access pattern inside a single library.*
- `TableMaint\clsAttorneySchedule.Save()`/`OnSave()` directly orchestrates an external service integration, pushing schedule entries to `SAIF.Services.Exchange` for calendar sync (suppressed outside Production via `AppGlobal.EnvironmentService.GetApplicationEnvironment()`).*
- `mdlCodeTables.vb` is called synchronously by most domain entities to populate lookup/dropdown data; it is a shared, stateless cross-cutting dependency rather than part of any aggregate's interaction chain.

## Design constraints
- **Duplicate MCO collection classes across libraries**: the sibling `SAIF.Business.View.Policy` library defines both `clsMCOCollection` and `clsPolicyMCOCollection`, which independently call the identical stored procedure `pk72846_view_policy.getmco` with identical parameters, differing only in the item type populated (`clsMCO` vs. `clsPolicyMCO`). This is legacy duplicate code consumed indirectly by this library's policy-lookup dependency chain and is flagged as technical debt rather than a documentation error.*
- **Non-parameterized `ValidateState()` SQL — injection risk**: `TableMaint\clsHearingLocation.vb` and `TableMaint\clsOtherFirm.vb` each implement an ad-hoc `ValidateState()` lookup against `ALL_STATES`/`NCCI_STATE_CODE` that builds its SQL via raw string concatenation of a user-suppliable `State` value rather than a bound parameter. This bypasses the standard `IBusinessCriteria` bind-variable pattern used elsewhere in this library and is a confirmed SQL-injection surface flagged for remediation (see Stage 1b DB analysis, DB-CLL-063/DB-CLL-064).
- **Hybrid SQL + REST data access within single aggregates**: several entities (`clsLegalCase`, `clsLetterRequest(Collection)`) mix Oracle SQL persistence with REST calls to the `LegalApi` integration tier, increasing the number of failure/consistency modes a caller must reason about.*
- **Retrieve-only and API-backed criteria as design guards**: 15 of 41 `IBusinessCriteria` implementations inherit `clsRetrieveOnlyBusinessCriteria`, which throws on any mutating SQL property access, enforcing read-only collection retrieval at the framework level rather than by convention.†
- **Environment-gated behavior**: `clsAttorneySchedule`, `clsConsolidations`, and `clsLegalSchedule` each branch on `AppGlobal.EnvironmentService.GetApplicationEnvironment()` to suppress non-Production side effects (e.g., Exchange calendar sync), meaning behavior differs between environments in ways not fully traceable from local source alone.*

## Architecture diagram
The diagram groups the library's 96 framework-derived classes into their functional sub-component clusters and shows their relationship to the framework base classes, the Oracle database, and the external REST/service integrations.

```mermaid
flowchart TD
    subgraph LegalCaseCore["Legal case core (LegalNet)"]
        LC[clsLegalCase /<br>clsLegalCaseCollection]
        CSH[clsCaseStatusHistory]
        FC[clsFindCase /<br>clsCaseSearchCriteria /<br>clsCaseSearchResult]
    end

    subgraph AppealsOutcomes["Appeals, board actions & outcomes"]
        AP[clsAppeal /<br>clsAppealExtension /<br>clsBoardRecord]
        CC[clsCaseCost]
        CO[clsCaseOutcome /<br>clsOutcomeIssue /<br>clsOutcomeStaff]
    end

    subgraph HearingsSchedule["Hearings, schedule & assignment"]
        HS[clsLegalSchedule /<br>clsHearingLocationInfo /<br>clsQuickCal]
        ASGN[clsAssignmentProcess /<br>clsAssignmentResult]
    end

    subgraph CaseAdmin["Case notes, mail, consolidation & acknowledge"]
        ACK[clsAcknowledge]
        CN[clsCaseNote /<br>clsMailDate /<br>clsConsolidations]
        RQ[clsRequestIssue /<br>clsLegalFileLocation /<br>clsOtherLegalParty]
    end

    subgraph TableMaint["Attorney / firm / person maintenance (TableMaint)"]
        ATT[clsAttorneyProfile /<br>clsAttorneyConflict /<br>clsAttorneyPolicyAssignment]
        LP[clsLegalPerson /<br>clsLegalPersonType /<br>clsOtherFirm]
        SCH[clsAttorneySchedule /<br>clsOutOFTownRotationAssgn]
        HL[clsHearingLocation]
    end

    subgraph LegalApiDTO["LegalApi (REST DTOs)"]
        DTO[Acknowledgement / FindCase /<br>BoardLog / WorkerAtty / etc.]
    end

    subgraph PrintLetters["Print (letter generation)"]
        PR[clsLetterRequest /<br>clsLetterRequestCollection]
    end

    CT[mdlCodeTables<br>code-table lookups]
    INST[Institutions.Designer.vb<br>typed DataSet]

    FWBASE["SAIF.Framework.Core:<br>clsBusinessBase, clsBusinessCollection,<br>clsBusinessCollectionBase,<br>clsRetrieveOnlyBusinessCriteria,<br>clsBusinessApiCriteriaBase, clsAddress"]

    ORACLE[(Oracle database<br>Pk80001_Legalnet / Pk80005_assignment)]
    LEGALAPI[LegalApi / integration<br>REST tier]
    EXCHANGE[SAIF.Services.Exchange]
    POLICY[SAIF.Business.View.Policy]

    FWBASE --> LegalCaseCore
    FWBASE --> AppealsOutcomes
    FWBASE --> HearingsSchedule
    FWBASE --> CaseAdmin
    FWBASE --> TableMaint
    FWBASE --> PrintLetters

    LegalCaseCore --> ORACLE
    AppealsOutcomes --> ORACLE
    HearingsSchedule --> ORACLE
    CaseAdmin --> ORACLE
    TableMaint --> ORACLE

    LegalCaseCore -->|CheckForOtherCases| LEGALAPI
    PrintLetters -->|v1/integration/*| LEGALAPI
    LegalApiDTO -.->|serializes| LegalCaseCore
    LegalApiDTO -.->|serializes| PrintLetters

    SCH -->|calendar sync| EXCHANGE
    ATT -->|policy validity check| POLICY

    CT -.-> TableMaint
    CT -.-> LegalCaseCore
    CT -.-> AppealsOutcomes
```

## Sequence diagram
The following diagram illustrates the representative core workflow of creating/updating a legal case, including its optional cross-tier delegation to the `LegalApi` REST integration.

```mermaid
sequenceDiagram
    participant Caller as Presentation caller
    participant LC as clsLegalCase
    participant Rules as clsRulesManager (Rules)
    participant Base as clsBusinessBase (framework)
    participant Portal as Data portal
    participant Oracle as Oracle (Pk80001_Legalnet)
    participant API as LegalApi REST tier

    Caller->>LC: Set properties (CaseTypeCode, RequestTypeCode, WcbNum, and other case fields)
    LC->>LC: MarkDirty()
    Caller->>LC: Save()
    LC->>Base: IsValid()
    Base->>Rules: CheckRules(businessObject)
    Rules-->>Base: broken-rule state
    Base->>Base: BeforeInsert / BeforeUpdate
    Base->>Portal: ProcessPortalRequest(InsertSQL/UpdateSQL)
    Portal->>Oracle: Pk80001_Legalnet.InsertLegalCase / UpdateLegalCase
    Oracle-->>Portal: RowsAffected
    Portal-->>Base: result
    Base->>Base: AfterInsert / AfterUpdate (check RowsAffected = 1)
    alt RowsAffected <> 1
        Base->>LC: AddErrorMessage("UpdateError","Update Failed")
    end
    LC->>API: CheckForOtherCases() (optional)
    API-->>LC: other-cases result
    LC-->>Caller: save result / broken rules
```

## Inherited framework behavior

The following statements describe base-class behavior inherited from `SAIF.Framework.Core`, retrieved from that library's own documentation via the Legends CLI RAG service:

- `clsBusinessBase` owns a `clsRulesManager` (`Rules`), supports `BeginEdit`/`CancelEdit`/`ApplyEdit` edit-session management, implements `IDataErrorInfo` for broken-rule surfacing to data-bound UI controls, and drives Save/Create/Retrieve through the data-portal dispatch path; `Save()`/`SaveChild()` throw `ApplicationException` if the target is read-only, in the wrong root/child role, still inside an edit level, or invalid after rule evaluation.†
- `clsBusinessCollection(Of T)` adds traversal members (`First`/`Next`/`Last`/`Previous`, `CurrentItem`, `IndexOf`) and collection-level `Save()`/`SaveChild()` that persists deferred deletions first, then active children, stopping at the first rule failure.†
- `clsBusinessCollectionBase` is the non-generic collection base used by `clsLetterRequestCollection`, providing the same traversal/error-aggregation surface without a strongly-typed item constraint.†
- `clsRetrieveOnlyBusinessCriteria` overrides `CreateSQL`/`InsertSQL`/`UpdateSQL`/`DeleteSQL` to throw `ApplicationException("SQL property not available.")` on access, and exposes a protected `SetRetrieveSQL(sql As String)` as the only supported way to populate retrieval SQL — enforcing the "retrieve-only criteria SQL suppression" rule (framework BR-003) used by 15 of this library's 41 `IBusinessCriteria` implementations.†
- `clsBusinessApiCriteriaBase` leaves all five SQL properties (`RetrieveSql`, `InsertSql`, `UpdateSql`, `DeleteSql`, `CreateSql`) returning the CLR default by design, and instead exposes `ApiRoutes`, `GetApiClient(apiClientKey As String, controller As String)`, and `FormatRoute(routeKey As String)` to resolve a named `IApiClient` and render REST routes — the mechanism this library's `clsCaseSearchResult` nested criteria and the entire `Print\` subsystem rely on (framework BR-004: "API criteria SQL properties are always empty by design").†
- `clsAddress`, inherited by `clsHearingLocationInfo` in this library, is documented at the library level in `SAIF.Framework.Core` but the RAG service returned no class-specific member/behavior detail for it beyond its presence in the framework's address/business-object model — its structured postal-address contribution to `clsHearingLocationInfo` is inferred from usage rather than confirmed from framework documentation.**

> **Note:** Statements marked with `†` are derived from dependency library
> documentation via the Legends CLI. Statements marked with `*` were inferred
> from code structure or contextual evidence. Statements marked with `**` could
> not be confirmed; treat as unknown until verified.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Database tables](database-tables.md)
- [SQL catalog](sql/index.md)
- [Configuration](configuration.md)
- [API reference](api/index.md)

## Sources
- `SAIF.Business.Claim.Legal\SAIF.Business.Claim.Legal.vbproj`
- `SAIF.Business.Claim.Legal\LegalNet\` (all `.vb` files)
- `SAIF.Business.Claim.Legal\TableMaint\` (all `.vb` files)
- `SAIF.Business.Claim.Legal\LegalApi\` (all `.vb` files)
- `SAIF.Business.Claim.Legal\mdlCodeTables.vb`
- `SAIF.Business.Claim.Legal\Web.config`, `app.config`
- `SAIF.Business.View.Policy\SAIF.Business.View.Policy.vbproj` (resolved framework types: `clsBusinessBase`, `clsBusinessCollection`, `clsBusinessCollectionBase`, `clsRetrieveOnlyBusinessCriteria`, `clsBusinessApiCriteriaBase`, `clsAddress` — Legends CLI RAG results from `SAIF.Framework.Core`)
